﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.Model;
using StockFinder.Services.MarketSmithScreenService;
using System.Net;
using System.IO;
using log4net;

namespace StockFinder.Services.Extractors.MarketSmith
{
    public class MarketSmithIBDCompositeExtractor
    {
        private static readonly ILog _Log = LogManager.GetLogger(typeof(MarketSmithIBDCompositeExtractor));

        /// <summary>
        /// Gets the entire list of IBD stocks and their ratings.
        /// Skips any result that has null value for any of the returned
        /// criteria
        /// </summary>
        /// <returns></returns>
        public Tuple<int, List<IBDRatings>> GetIBDRatingsFromMarketSmith()
        {
            List<IBDRatings> list = new List<IBDRatings>();

            CookieContainer cookieContainer = new CookieContainer();

            _Log.Debug("Accessing MarketSmith main site to get initial cookies...");

            #region Access main site first

            var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.marketsmith.com");
            httpWebRequest.CookieContainer = cookieContainer;
            httpWebRequest.Accept = "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-silverlight, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, #/#";
            httpWebRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1) Gecko/20090624 Firefox/3.5";
            httpWebRequest.KeepAlive = true;
            httpWebRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
            httpWebRequest.Method = "GET";
            httpWebRequest.ContentType = "application/x-www-form-urlencoded";
            var webResponse = (HttpWebResponse)httpWebRequest.GetResponse();

            #endregion

            _Log.Debug("Logging in with cookies");

            #region Login

            httpWebRequest = (HttpWebRequest)WebRequest.Create("https://www.marketsmith.com/Secure/Login.aspx/Login");
            httpWebRequest.ContentType = "application/json; charset=utf-8";
            httpWebRequest.Method = "POST";
            httpWebRequest.CookieContainer = cookieContainer;

            using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
            {
                string json = "{\"username\":\"ssattin@gmail.com\",\"password\":\"dennis10\",\"rememberMe\":\"true\",\"trys\":\"1\",\"currentUrl\":\"http://www.marketsmith.com\"}";

                streamWriter.Write(json);
            }
            var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
            using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
            {
                var responseText = streamReader.ReadToEnd();
                //Now you have your response.
                //or false depending on information in the response               
            }

            #endregion

            _Log.Debug("Access main site again to reget logged in session cookies");

            #region Access main site again with cookies

            httpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.marketsmith.com");
            httpWebRequest.CookieContainer = cookieContainer;
            httpWebRequest.Accept = "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-silverlight, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, #/#";
            httpWebRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1) Gecko/20090624 Firefox/3.5";
            httpWebRequest.KeepAlive = true;
            httpWebRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
            httpWebRequest.Method = "GET";
            httpWebRequest.ContentType = "application/x-www-form-urlencoded";
            webResponse = (HttpWebResponse)httpWebRequest.GetResponse();

            #endregion

            _Log.Debug("Getting first screen result to get total row count");

            #region Get screen

            GenScreenerSvc sv = new GenScreenerSvc();
            sv.CookieContainer = cookieContainer;
            sv.Url = "http://webservices.marketsmith.com/WONServices/GenScreener/GenScreener.svc";
            sv.Timeout = -1;

            int PAGE_SIZE = 50;

            ScreenMessageIn s = new ScreenMessageIn();
            s.cacheID = -1;
            s.screenID = 86743;
            s.userID = 305410595179635;
            s.benchmarkScreenID = 1;
            s.templateID = 245620;
            s.pageNumbers = "1";
            s.pageSize = PAGE_SIZE;

            var output = sv.GetScreenResult(s);            

            //1. get the total number of rows
            int totalRows = output.content.listPanelResult.totalRows;

            _Log.DebugFormat("Total rows: {0}", totalRows);

            decimal numberOfPages = Math.Ceiling((decimal)totalRows / (decimal)PAGE_SIZE);

            _Log.DebugFormat("Number of pages: {0}", numberOfPages);

            List<IBDRatings> ratings = null;
            bool success = false;

            //loop each page and get the output
            for (int i = 1; i <= numberOfPages; i++)
            {
                _Log.DebugFormat("Screen request {0}/{1}", i, numberOfPages);
                success = false;

                s.pageNumbers = i.ToString();

                for (int tries = 0; tries < 5; i++)
                {
                    try
                    {
                        output = sv.GetScreenResult(s);
                        success = true;
                        break;
                    }
                    catch (Exception exception)
                    {
                        _Log.ErrorFormat("Try {0} failed, trying again --> {1}", tries + 1, exception);
                    }
                }

                //something happened with getting screen results
                if (!success)
                {
                    //so quit with nothing
                    return null;
                }

                ratings = GetIBDRatingsFromMarketSmithOutput(output);

                foreach (var item in ratings)
                {
                    list.Add(item);
                }

                _Log.DebugFormat("Total output: {0}", list.Count);
            }

            #endregion 

            return new Tuple<int,List<IBDRatings>>(totalRows, list);
        }

        private const int SYMBOL_COLUMNHEADER_INDEX = 2;
        private const int EPS_RATING_COLUMNHEADER_INDEX = 10;
        private const int RS_RATING_COLUMNHEADER_INDEX = 11;
        private const int GROUPRS_COLUMNHEADER_INDEX = 12;
        private const int SMRRATING_COLUMNHEADER_INDEX = 13;
        private const int ADRATING_COLUMNHEADER_INDEX = 14;
        private const int COMPOSITE_COLUMNHEADER_INDEX = 15;

        private List<IBDRatings> GetIBDRatingsFromMarketSmithOutput(ScreenMessageOut output)
        {
            List<IBDRatings> list = new List<IBDRatings>();
            IBDRatings rating = null;

            int columnHeaderIndex = -1;
            int counter = 0;

            _Log.DebugFormat("Got {0} rows", output.content.listPanelResult.instrumentRows.Count());

            foreach (var item in output.content.listPanelResult.instrumentRows)
            {
                rating = new IBDRatings();

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "Symbol");
                if (item.valueList[columnHeaderIndex].value == null) continue;
                rating.Symbol = (string)item.valueList[columnHeaderIndex].value;

                _Log.DebugFormat("Found symbol: {0}", rating.Symbol);

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "EPS Rating");
                if (item.valueList[columnHeaderIndex].value == null) rating.EPS = -1;
                else rating.EPS = Convert.ToInt32(item.valueList[columnHeaderIndex].value.ToString());

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "RS Rating");
                if (item.valueList[columnHeaderIndex].value == null) rating.RelativeStrength = -1;
                else rating.RelativeStrength = Convert.ToInt32(item.valueList[columnHeaderIndex].value.ToString());

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "Ind Group RS");
                if (item.valueList[columnHeaderIndex].value == null) rating.GroupRSRating = "N/A";
                else rating.GroupRSRating = (string)item.valueList[columnHeaderIndex].value;

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "SMR Rating");
                if (item.valueList[columnHeaderIndex].value == null) rating.SMR = "N/A";
                else rating.SMR = (string)item.valueList[columnHeaderIndex].value;

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "A/D Rating");
                if (item.valueList[columnHeaderIndex].value == null) rating.AccDist = "N/A";
                else rating.AccDist = (string)item.valueList[columnHeaderIndex].value;

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "Comp Rating");
                if (item.valueList[columnHeaderIndex].value == null) rating.IBDComposite = -1;
                else rating.IBDComposite = Convert.ToInt32(item.valueList[columnHeaderIndex].value.ToString());

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "Type");
                if (item.valueList[columnHeaderIndex].value == null) rating.StockType = "N/A";
                else rating.StockType = (string)(item.valueList[columnHeaderIndex].value.ToString());

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "ETF/Closed-End Fund");
                if (item.valueList[columnHeaderIndex].value == null) rating.IsETFOrClosedEndFund = false;
                else rating.IsETFOrClosedEndFund = ((item.valueList[columnHeaderIndex].value.ToString()) == "1");

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "ETF");
                if (item.valueList[columnHeaderIndex].value == null) rating.IsETF = false;
                else rating.IsETF = ((item.valueList[columnHeaderIndex].value.ToString()) == "1");

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "Avg True Range");
                if (item.valueList[columnHeaderIndex].value == null) rating.AverageTrueRange = -1;
                else rating.AverageTrueRange = Convert.ToDecimal(item.valueList[columnHeaderIndex].value.ToString());

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "52-Wk High");
                if (item.valueList[columnHeaderIndex].value == null) rating.YearHigh = -1;
                else rating.YearHigh = Convert.ToDecimal(item.valueList[columnHeaderIndex].value.ToString());

                columnHeaderIndex = GetColumnHeaderIndexByName(output.content.listPanelResult.columnHeaders, "52-Wk Low");
                if (item.valueList[columnHeaderIndex].value == null) rating.YearLow = -1;
                else rating.YearLow = Convert.ToDecimal(item.valueList[columnHeaderIndex].value.ToString());

                rating.Date = DateTime.Now.Date;

                list.Add(rating);
                counter++;
                _Log.DebugFormat("Counter: {0}", counter);
            }

            return list;
        }

        private int GetColumnHeaderIndexByName(TableTemplateHeaderType[] tableTemplateHeaderType, string name)
        {
            int result = -1;

            TableTemplateHeaderType item = null;
            for (int i = 0; i < tableTemplateHeaderType.Length; i++)
            {
                item = tableTemplateHeaderType[i];

                if (item.name == name)
                {
                    result = i;
                    break;
                }
            }

            return result;
        }
    }
}
